/*
 * 简单向量实现: 向量长度,线性运算(+,-,数乘,数除), 内积(点乘)
 * 固定大小向量
 *
 * 历史:
 *	2019-12-15 姚彧 创建
 *  2019-12-16 ...  加入名字空间yy::math::
 *                  使用vs2019进行文件格式化
 * 					(x,y,z,w)初始化
 *  2019-12-30 ...  名字空间改为qk
 */

#ifndef _QK_FVECTOR_HPP_
#define _QK_FVECTOR_HPP_

#define FVECTOR FVector<n,Real>
#define FVECTOR_TEMPLATE template<int n, class Real>

#include <cmath>
#include <cstring>
#include <initializer_list>
#include <algorithm>
#include <assert.h>

namespace qk
{
	namespace math
	{
		template<int _n, class Real>
		struct FVector
		{
			typedef Real		value_type;

			Real v[_n];
			int n;

			Real length() const { return sqrt(Dot(*this, *this)); }
			Real length2() const { return Dot(*this, *this); }

			FVector() :n(_n) { makeZero(); }
			FVector(Real _x, Real _y) :n(_n) { assert(n >= 2); makeZero(); x() = _x; y() = _y; }
			FVector(Real _x, Real _y, Real _z) :n(_n) { assert(n >= 3); makeZero(); x() = _x;  y() = _y; z() = _z; }
			FVector(Real _x, Real _y, Real _z, Real _w) :n(_n) { assert(n >= 4); makeZero();  x() = _x; y() = _y; z() = _z; w() = _w; }
			FVector(std::initializer_list<Real>values) :n(_n)
			{
				int i = 0;
				makeZero();
				for (auto iter = values.begin(); i < n && iter != values.end(); ++i, ++iter)
					v[i] = *iter;
			}

			// 一维下标运算符
			Real& operator[](int i) { return v[i]; }
			const Real& operator[](int i) const { return v[i]; }

			// x,y,z,w分量访问方式
			Real& x() { return v[0]; }
			const Real& x() const { return v[0]; }
			Real& y() { return v[1]; }
			const Real& y() const { return v[1]; }
			Real& z() { return v[2]; }
			const Real& z() const { return v[2]; }
			Real& w() { return v[3]; }
			const Real& w() const { return v[3]; }

			// 0(向量)
			FVector& makeZero()
			{
				memset(v, 0, sizeof(v));
				return *this;
			}

			// 1(标准向量)
			FVector& makeIdentity(int i)
			{
				makeZero();
				v[i] = (Real)1;
				return *this;
			}
		};

		// 一元运算符
		FVECTOR_TEMPLATE
			FVECTOR operator-(FVECTOR a)
		{
			for (int i = 0; i < n; ++i)
				a[i] = -a[i];
			return a;
		}

		// 线性运算
		FVECTOR_TEMPLATE
			FVECTOR operator+(FVECTOR a, FVECTOR const& b)
		{
			return a += b;
		}

		FVECTOR_TEMPLATE
			FVECTOR& operator+=(FVECTOR& a, FVECTOR const& b)
		{
			for (int i = 0; i < n; ++i)
				a[i] += b[i];
			return a;
		}

		FVECTOR_TEMPLATE
			FVECTOR operator-(FVECTOR a, FVECTOR const& b)
		{
			return a -= b;
		}

		FVECTOR_TEMPLATE
			FVECTOR& operator-=(FVECTOR& a, FVECTOR const& b)
		{
			for (int i = 0; i < n; ++i)
				a[i] -= b[i];
			return a;
		}

		FVECTOR_TEMPLATE
			FVECTOR operator*(FVECTOR a, Real k)
		{
			return a *= k;
		}

		FVECTOR_TEMPLATE
			FVECTOR operator*(Real k, FVECTOR a)
		{
			return a *= k;
		}

		template<int n, class Real, class T>
		FVECTOR& operator*=(FVECTOR& a, T k)
		{
			Real k0 = k;
			for (int i = 0; i < n; ++i)
				a[i] *= k0;
			return a;
		}

		template<int n, class Real, class T>
		FVECTOR operator/(FVECTOR a, T k)
		{
			return a /= k;
		}

		template<int n, class Real, class T>
		FVECTOR& operator/=(FVECTOR& a, T k)
		{
			Real k0 = k;
			if (k0 != (Real)0)
				a *= (Real)1 / k0;
			else
				a.makeZero();
			return a;
		}

		// 内积(点乘)
		FVECTOR_TEMPLATE
			Real Dot(FVECTOR const& a, FVECTOR const& b)
		{
			Real s = 0;
			for (int i = 0; i < n; ++i)
				s += a[i] * b[i];
			return s;
		}

		// 外积(叉乘)
		FVECTOR_TEMPLATE
			FVECTOR Cross(FVECTOR const& a, FVECTOR const& b)
		{
			static_assert(n == 3 || n == 4, "维数应该是3或4.");
			FVECTOR c;
			c.makeZero();
			c[0] = a[1] * b[2] - a[2] * b[1];
			c[1] = a[2] * b[0] - a[0] * b[2];
			c[2] = a[0] * b[1] - a[1] * b[0];
			return c;
		}
	}
}

#endif	//_QK_FVECTOR_HPP_